/**
 * Copyright  (c) 2009-2010 Wilmar IT Service,  Inc.   
 * All  rights  reserved. 
 */
package com.wilmar.process.core.services.impl;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.log4j.Logger;

import com.wilmar.process.core.services.api.ISystemSubProcessInstanceRelationService;
import com.wilmar.process.dao.api.ISubProcessInstanceRelationDAO;
import com.wilmar.process.entity.SubProcessInstanceRelation;
import com.wilmar.process.entity.query.SubProcessinstanceRelationQueryObject;
import com.wilmar.process.entity.vo.SubProcessInstanceRelationVO;
import com.wilmar.process.exception.ObjectNotFoundException;

/**
 * @author makubex Email:makubexnet@gmail.com
 * @version 1.0.0 Jun 17, 2010
 * @since 1.0.0
 */
public class SystemSubProcessInstanceRelationServiceImpl implements
		ISystemSubProcessInstanceRelationService {
	private static final Logger log = Logger
			.getLogger(SystemSubProcessInstanceRelationServiceImpl.class);

	private ISubProcessInstanceRelationDAO subProcessInstanceRelationDAO;

	/**
	 * @return the subProcessInstanceRelationDAO
	 */
	public ISubProcessInstanceRelationDAO getSubProcessInstanceRelationDAO() {
		return subProcessInstanceRelationDAO;
	}

	/**
	 * @param subProcessInstanceRelationDAO
	 *            the subProcessInstanceRelationDAO to set
	 */
	public void setSubProcessInstanceRelationDAO(
			ISubProcessInstanceRelationDAO subProcessInstanceRelationDAO) {
		this.subProcessInstanceRelationDAO = subProcessInstanceRelationDAO;
	}

	/**
	 * @see com.wilmar.process.core.services.api.ISystemSubProcessInstanceRelationService#save(com.wilmar.process.entity.SubProcessInstanceRelation)
	 */
	public void saveRelation(
			SubProcessInstanceRelation subProcessInstanceRelation) {
		this.subProcessInstanceRelationDAO.save(subProcessInstanceRelation);
	}

	/**
	 * @see com.wilmar.process.core.services.api.IBaseService#convertToVO(java.lang.Object)
	 */
	public SubProcessInstanceRelationVO convertToVO(
			SubProcessInstanceRelation entity) {
		SubProcessInstanceRelationVO vo = new SubProcessInstanceRelationVO(
				entity);
		return vo;
	}

	/**
	 * @see com.wilmar.process.core.services.api.IBaseService#convertToVOList(java.util.Collection)
	 */
	public List<SubProcessInstanceRelationVO> convertToVOList(
			Collection<SubProcessInstanceRelation> entityCollection) {
		List<SubProcessInstanceRelationVO> volist = new ArrayList<SubProcessInstanceRelationVO>(
				entityCollection.size());
		for (SubProcessInstanceRelation pojo : entityCollection) {
			volist.add(this.convertToVO(pojo));
		}
		return volist;
	}

	/**
	 * @see com.wilmar.process.core.services.api.ISystemSubProcessInstanceRelationService#findAllSubInstanceExids(java.lang.String)
	 */
	public Set<String> findAllSubInstanceExids(String parentInstanceExid)
			throws ObjectNotFoundException {
		log.debug("Finding sub instance executions...");
		Set<String> subs = this.findSubInstanceExids(parentInstanceExid);
		Set<String> result = subs;
		if (subs != null && !subs.isEmpty()) {
			for (String subexid : subs) {
				Set<String> tmp = null;
				try {
					tmp = this.findAllSubInstanceExids(subexid);
					result.addAll(tmp);
				} catch (ObjectNotFoundException ex) {
					try {
						tmp = this.findSubInstanceExids(subexid);
						result.addAll(tmp);
					} catch (ObjectNotFoundException ex2) {
						log.debug(ex2.getMessage());
						continue;
					}
				}
			}
		}
		return result;
	}

	/**
	 * @see com.wilmar.process.core.services.api.ISystemSubProcessInstanceRelationService#findParentInstanceExid(java.lang.String)
	 */
	public String findParentInstanceExid(String subInstanceExid)
			throws ObjectNotFoundException {
		SubProcessInstanceRelation exampleInstance = new SubProcessInstanceRelation();
		exampleInstance.setSubExid(subInstanceExid);
		List<SubProcessInstanceRelation> entityList = this.subProcessInstanceRelationDAO
				.getListByExample(exampleInstance);
		if (entityList == null || entityList.isEmpty()) {
			log.debug("This is the root instance!");
			throw new ObjectNotFoundException(
					"Here is no parent instance for this instance: "
							+ subInstanceExid);
		}
		return entityList.get(0).getParentExid();
	}

	/**
	 * @see com.wilmar.process.core.services.api.ISystemSubProcessInstanceRelationService#findRootInstanceExid(java.lang.String)
	 */
	public String findRootInstanceExid(String subInstanceExid) {
		String result = subInstanceExid;
		try {
			while (true) {
				result = this.findParentInstanceExid(result);
			}
		} catch (ObjectNotFoundException ex) {
			if (result == null)
				result = subInstanceExid;
		}
		log.debug("Root is: " + result);
		return result;
	}

	/**
	 * @see com.wilmar.process.core.services.api.ISystemSubProcessInstanceRelationService
	 *      #findSubInstanceExids(java.lang.String)
	 */
	public Set<String> findSubInstanceExids(String parentInstanceExid)
			throws ObjectNotFoundException {
		SubProcessInstanceRelation exampleInstance = new SubProcessInstanceRelation();
		exampleInstance.setParentExid(parentInstanceExid);
		List<SubProcessInstanceRelation> entityList = this.subProcessInstanceRelationDAO
				.getListByExample(exampleInstance);
		if (entityList == null || entityList.isEmpty())
			throw new ObjectNotFoundException(
					"Here is no sub instance for this instance: "
							+ parentInstanceExid);
		Set<String> result = new HashSet<String>();
		for (SubProcessInstanceRelation rel : entityList)
			result.add(rel.getSubExid());
		return result;
	}

	/**
	 * @see com.wilmar.process.core.services.api.ISystemSubProcessInstanceRelationService
	 *      #getDetail(java.lang.Long)
	 */
	public SubProcessInstanceRelation getDetail(Long relationId)
			throws ObjectNotFoundException {
		SubProcessInstanceRelation result = this.subProcessInstanceRelationDAO
				.getDetail(relationId);
		if (result == null) {
			log.debug("No result with finding relation!");
			throw new ObjectNotFoundException(
					"Could not find the relation by id: " + relationId);
		}
		return result;
	}

	/**
	 * @see com.wilmar.process.core.services.api.ISystemSubProcessInstanceRelationService
	 *      #removeAllRelation(java.lang.String)
	 */
	public synchronized void removeAllRelation(String parentInstanceExid) {
		log.debug("Removing all relation...");
		try {
			Set<String> subExids = this
					.findSubInstanceExids(parentInstanceExid);
			for (String subExid : subExids) {
				this.removeAllRelation(subExid);
			}
			this.removeRelation(parentInstanceExid);
		} catch (ObjectNotFoundException e) {
			this.removeRelation(parentInstanceExid);
		}
	}

	/**
	 * @see com.wilmar.process.core.services.api.ISystemSubProcessInstanceRelationService
	 *      #removeRelation(java.lang.String)
	 */
	public synchronized void removeRelation(String subInstanceExid) {
		log.debug("Removing relation by sub instance: " + subInstanceExid);
		SubProcessinstanceRelationQueryObject queryObj = new SubProcessinstanceRelationQueryObject();
		queryObj.setPsRelationMap(queryObj.new RelationCondition(null,
				subInstanceExid));
		List<SubProcessInstanceRelation> list = this.subProcessInstanceRelationDAO
				.getListByQueryObject(queryObj);
		if (list != null && !list.isEmpty()) {
			SubProcessInstanceRelation rel = list.get(0);
			this.subProcessInstanceRelationDAO.remove(rel);
		}
	}

	/**
	 * @see com.wilmar.process.core.services.api.ISystemSubProcessInstanceRelationService
	 *      #removeRelation(java.lang.String, java.lang.String)
	 */
	public synchronized void removeRelation(String parentInstanceExid,
			String subInstanceExid) {
		log.debug("Removing relation by parent instance: " + parentInstanceExid
				+ " and sub instance: " + subInstanceExid);
		SubProcessinstanceRelationQueryObject queryObj = new SubProcessinstanceRelationQueryObject();
		queryObj.setPsRelationMap(queryObj.new RelationCondition(
				parentInstanceExid, subInstanceExid));
		List<SubProcessInstanceRelation> list = this.subProcessInstanceRelationDAO
				.getListByQueryObject(queryObj);
		if (list != null && !list.isEmpty()) {
			SubProcessInstanceRelation rel = list.get(0);
			this.subProcessInstanceRelationDAO.remove(rel);
		}
	}
}
